feat: warn on unmerged sync PR and add --direct-merge#13
Merged
Conversation
Two tweaks to `cella sync` to stop forgotten sync PRs from piling up. Pre-flight guard: before cutting a fresh sync branch, check for an open sync PR (head branch under `cella/sync/`) via `gh`. Because the last-sync point lives in the manifest committed *on the branch*, a new cycle cut from a trunk that still lacks a merged sync PR re-includes that PR's whole delta — the "why so many changes" surprise. The guard offers to squash-merge the open PR first (fast-forwarding the local trunk so the new cycle cuts clean), continue anyway, or cancel. A PR GitHub refuses to merge (conflicts / failing required checks) stops the run with guidance. Degrades to a no-op without `gh`, with no open sync PR, or in a non-interactive session. --direct-merge: once the sync PR is open, enable GitHub auto-merge (squash) so it merges itself when required checks pass. Opt-in per run; release-please is unaffected (it watches the trunk for the one squashed `chore:` commit either way). New `src/utils/gh.ts` consolidates the `gh` wrappers (list/merge/close) behind pure, unit-tested helpers (`filterSyncPrs`, `buildMergeArgs`). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Running
pnpm cella syncagain before merging the previous sync PR silently stacks changes: the last-sync point lives incella.manifest.jsoncommitted on the sync branch, so a new cycle cut from a trunk that still lacks the merged PR re-includes that PR's entire delta on top of the new upstream commits — the "why are there suddenly so many changes" surprise.Two tweaks address this.
1. Pre-flight guard for an unmerged sync PR
Before cutting a fresh sync branch,
cella syncnow checks for an open sync PR (head branch undercella/sync/) viaghand prompts:gh pr merge --squash --delete-branchthe open PR, then fast-forward the local trunk so the new cycle cuts clean. A PR GitHub refuses to merge (conflicts / failing required checks — the "breaking changes" to fix first) stops the run with guidance.Multiple stacked sync PRs: the newest is a content superset, so it is merged and the older ones are closed.
Degrades to a silent no-op when it can't help: no
gh, no open sync PR, or a non-interactive session (no TTY).2.
--direct-mergeflagOnce the sync PR is open, enables GitHub auto-merge (squash) so it merges itself as soon as required checks pass — no forgotten open PR to trip over next time. Opt-in per run (deliberately not a config default — a sync PR is usually worth a human look), and needs auto-merge enabled on the repo. Falls back to printing the manual command if the repo does not allow it.
release-please is unaffected either way: it watches the trunk for the single squashed
chore: sync upstream cella …commit, which lands identically whether the PR is merged by hand, by the guard, or by auto-merge (the branch is already flattened to one commit before pushing).Implementation
src/utils/gh.tsconsolidates the scatteredghcalls behind small wrappers (ghAvailable,listOpenSyncPrs,mergePrSquash,closePr) with pure, unit-tested cores (filterSyncPrs,buildMergeArgs).src/services/sync.ts:guardAgainstOpenSyncPr/mergeOpenSyncPrsin the fresh-cycle path;enableAutoMergeinshipSyncBranch.--direct-mergewired throughcli.ts+RuntimeConfig.Tests
tests/gh.test.ts—filterSyncPrs(prefix boundaries) andbuildMergeArgs(flag combinations).tests/cli.test.ts—sync --direct-mergeparsing.pnpm ts+pnpm biome checkclean; verifiedsync --helplists the flag afterpnpm build.The
gh-network paths degrade to a no-op withoutgh, which is exactly the e2e condition, so the existing e2e suite is untouched.🤖 Generated with Claude Code